<template>
  <div class="flex h-screen">

    <!-- Left section occupying 2/3 of the page -->
    <div class="flex flex-col w-2/3 border-r border-gray-300">
      <div
        class="flex flex-nowrap fixed w-full items-baseline top-0 px-6 py-5 bg-gray-100"
      >
        <div class="text-2xl font-bold">AuditLLM </div>
        <div class="ml-4 text-sm text-gray-500">
          审元
        （联系人：詹天明，联系电话：13584037818（微信同号））
        </div>
        <div
          class="ml-auto px-3 py-2 text-sm cursor-pointer hover:bg-white rounded-md"
          @click="clickConfig()"
        >
          设置
        </div>
      </div>

      <div class="flex-1 mx-2 mt-20 mb-2" ref="chatListDom">
        <div
          class="group flex flex-col px-4 py-3 hover:bg-slate-100 rounded-lg"
          v-for="item of messageList.filter((v) => v.role !== 'system')"
        >
          <div class="flex justify-between items-center mb-2">
            <div class="font-bold">{{ roleAlias[item.role] }}：</div>
            <Copy class="invisible group-hover:visible" :content="item.content" />
          </div>
          <div>
            <div
              class="text-sm text-slate-600 leading-relaxed"
              v-if="item.content"
              v-html="md.render(item.content)"
            ></div>
            <!-- 等待回答返回 加载效果p -->
            <Loding v-else />
          </div>
        </div>
      </div>

      <div class="flex flex-col w-full ">
        <div class="flex w-2/3 gap-1 justify-between px-6 py-2">
          <button class="btn bg-blue-300 text-white px-4 py-1 rounded-full hover:bg-blue-500 text-sm">查证（国家级）</button>
          <button class="btn bg-blue-300 text-white px-4 py-1 rounded-full hover:bg-blue-500 text-sm">查证（内审级）</button>
          <button class="btn bg-blue-300 text-white px-4 py-1 rounded-full hover:bg-blue-500 text-sm">查证（企业级）</button>
          <button class="btn bg-blue-300 text-white px-4 py-1 rounded-full hover:bg-blue-500 text-sm">知识问答</button>
          <button class="btn bg-blue-300 text-white px-4 py-1 rounded-full hover:bg-blue-500 text-sm">案例推荐</button>
           <button class="btn bg-red-300 text-white px-4 py-1 rounded-full hover:bg-blue-500 text-sm"   @click="clear()">清空</button>
        </div>
      </div>      

      <div class="sticky bottom-0 w-full p-6 pb-8 bg-gray-100">
        <div class="flex">
          <input
            class="input"
            :type="isConfig ? 'password' : 'text'"
            :placeholder="isConfig ? 'sk-xxxxxxxxxx' : '请输入'"
            v-model="messageContent"
            @keydown.enter="isTalking || sendOrSave()"
          />
          <button class="btn bg-blue-500" :disabled="isTalking" @click="sendOrSave()">
            {{ isConfig ? "保存" : "发送" }}
          </button>
        </div>
      </div>
    </div>

    <!-- 右边区域 -->
    <div class="fixed top-0 right-0 w-1/3 h-screen bg-gray-50 p-4 flex flex-col">
      <!-- 平均分为6份 -->
      <div style="flex-grow: 3.5;"></div>
      <!--模型选择按钮-->
      <div class="flex space-x-5">
          <button class="btn bg-blue-300 text-white px-6 py-2 rounded-full hover:bg-blue-500 text-sm">大模型1</button>
          <button class="btn bg-blue-300 text-white px-6 py-2 rounded-full hover:bg-blue-500 text-sm">大模型2</button>
      </div>
      <div style="flex-grow: 3;"></div>
      <!--参数选择-->
      <div class="flex flex-col space-y-7">
        <div class="flex items-center space-x-4">
          <label for="slider1" class="text-gray-700">文本长度&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
          <input type="range" id="slider1" name="slider1" min="0" max="1024" value="500" class="slider w-64" @input="updateSliderValue1" />
          <output class="text-gray-700" for="slider1">{{ SliderValue1 }}</output>
        </div>
        <div class="flex items-center space-x-4">
          <label for="slider2" class="text-gray-700">历史对话轮次</label>
          <input type="range" id="slider2" name="slider2" min="0" max="5" value="1" class="slider w-64" @input="updateSliderValue2">
          <output class="text-gray-700" for="slider2">{{ SliderValue2 }}</output>
        </div>
        
      </div>
      <div style="flex-grow: 20;"></div>
      <!--知识库-->
      <button class="btn bg-blue-300 text-white px-6 py-2 rounded-full hover:bg-blue-500 text-sm">知识库</button>
      <div style="flex-grow: 6;"></div>
      
  </div>

  </div>
</template>

<script setup lang="ts">
import type { ChatMessage } from "@/types";
import { ref, watch, nextTick, onMounted } from "vue";
import { chat } from "@/libs/auditllm";
import cryptoJS from "crypto-js";
import Loding from "@/components/Loding.vue";
import Copy from "@/components/Copy.vue";
import { md } from "@/libs/markdown";
import axios from '@/axios';

let apiKey = "";
let isConfig = ref(false);
let isTalking = ref(false);
let messageContent = ref("");
let smallModelProbability = ref("")
const chatListDom = ref<HTMLDivElement>();
const decoder = new TextDecoder("utf-8");
const roleAlias = { user: "问题", assistant: "AA", system: "System" };
const messageList = ref<ChatMessage[]>([
  {
    role: "system",
    content: "你是审计大模型 AuditLLm，尽可能简洁地回答。",
  },
  {
    role: "assistant",
    content: `你好，我是AUditLLM，我可以提供一些常用服务和信息，例如：

1. 审计常识问答审计常识问答：涵盖审计定义、类型、程序、内部控制、财务报表审计、合规性审计、风险管理、专业道德和审计证据等方面的内容。。

2. 审计定性推荐：如果你有任何问题需要咨询，例如包含对组织内部控制的评估和改进建议，以提高合规性、风险管理和运营效率等，我可以尽可能为你提供帮助。


请告诉我你需要哪方面的帮助，我会根据你的需求给你提供相应的信息和建议。`,
  },
]);

onMounted(() => {
  if (getAPIKey()) {
    switchConfigStatus();
  }
});

const sendChatMessage = async (content: string = messageContent.value) => {
  try {
    isTalking.value = true;
    if (messageList.value.length === 2) {
      messageList.value.pop();
    }
    messageList.value.push({ role: "user", content });
    
    messageList.value.push({ role: "assistant", content: "" });
    const res = await  chat(messageList.value, messageContent.value)
    clearMessageContent();
    // const { body, status } = await chat(messageList.value, getAPIKey());
    
    
    //const res = await  chat(messageList.value, messageContent.value)

    if (res) {
      // 进行打字效果
      type(res);
    }
  } catch (error: any) {
    appendLastMessageContent(error);
  } finally {
    isTalking.value = false;
  }
};

// 通过分割字符串打字效果
const type = async (content: string) => {
  let curIndex = 0
  const probabilityTimer = setInterval(() => {
    //先清空
    smallModelProbability.value = ""
    smallModelProbability.value = content[curIndex];
    if (curIndex <  content.length) {
      curIndex++;
      appendLastMessageContent(smallModelProbability.value)
    }
    else {
      clearInterval(probabilityTimer);
    }
  }, 20)    //20是时间间隔
}

const readStream = async (
  reader: ReadableStreamDefaultReader<Uint8Array>,
  status: number
) => {
  let partialLine = "";

  while (true) {
    // eslint-disable-next-line no-await-in-loop
    const { value, done } = await reader.read();
    if (done) break;

    const decodedText = decoder.decode(value, { stream: true });

    if (status !== 200) {
      const json = JSON.parse(decodedText); // start with "data: "
      const content = json.error.message ?? decodedText;
      appendLastMessageContent(content);
      return;
    }

    const chunk = partialLine + decodedText;
    const newLines = chunk.split(/\r?\n/);

    partialLine = newLines.pop() ?? "";

    for (const line of newLines) {
      if (line.length === 0) continue; // ignore empty message
      if (line.startsWith(":")) continue; // ignore sse comment message
      if (line === "data: [DONE]") return; //

      const json = JSON.parse(line.substring(6)); // start with "data: "
      const content =
        status === 200
          ? json.choices[0].delta.content ?? ""
          : json.error.message;
      appendLastMessageContent(content);
    }
  }
};

const appendLastMessageContent = (content: string) =>
  (messageList.value[messageList.value.length - 1].content += content);

const sendOrSave = () => {
  if (!messageContent.value.length) return;
  if (isConfig.value) {
    if (saveAPIKey(messageContent.value.trim())) {
      switchConfigStatus();
    }
    clearMessageContent();
  } else {
    sendChatMessage();
  }
};

const clear = () => {
  let i: number
    for (i = 0; i <  messageList.value.length; i++){
      messageList.value.pop();
    }

};

const clickConfig = () => {
  if (!isConfig.value) {
    messageContent.value = getAPIKey();
  } else {
    clearMessageContent();
  }
  switchConfigStatus();
};

const getSecretKey = () => "lianginx";

const saveAPIKey = (apiKey: string) => {
  if (apiKey.slice(0, 3) !== "sk-" || apiKey.length !== 51) {
    alert("API Key 错误，请检查后重新输入！");
    return false;
  }
  const aesAPIKey = cryptoJS.AES.encrypt(apiKey, getSecretKey()).toString();
  localStorage.setItem("apiKey", aesAPIKey);
  return true;
};

const getAPIKey = () => {
  if (apiKey) return apiKey;
  const aesAPIKey = localStorage.getItem("apiKey") ?? "";
  apiKey = cryptoJS.AES.decrypt(aesAPIKey, getSecretKey()).toString(
    cryptoJS.enc.Utf8
  );
  return apiKey;
};

const switchConfigStatus = () => (isConfig.value = !isConfig.value);

const clearMessageContent = () => (messageContent.value = "");

const scrollToBottom = () => {
  if (!chatListDom.value) return;
  scrollTo(0, chatListDom.value.scrollHeight);
};

watch(messageList.value, () => nextTick(() => scrollToBottom()));
//滑动栏操作，滑动后1s向后端发送数据
const SliderValue1 = ref(500); 
const SliderValue2 = ref(1); 
    let debounceTimer: number | null = null; 

    const updateSliderValue1 = (event: Event) => {
      const target = event.target as HTMLInputElement;
      SliderValue1.value = parseInt(target.value, 10);
    };

    const updateSliderValue2 = (event: Event) => {
      const target = event.target as HTMLInputElement;
      SliderValue2.value = parseInt(target.value, 10);
    };

    const debounceSendDataToBackend = (newValue: number) => {
      if (debounceTimer !== null) {
        clearTimeout(debounceTimer);
      }
      debounceTimer = setTimeout(() => {
        sendDataToBackend(newValue);
      }, 1000); 
    };

    const debounceSendDataToBackend2 = (newValue: number) => {
      if (debounceTimer !== null) {
        clearTimeout(debounceTimer);
      }
      debounceTimer = setTimeout(() => {
        sendDataToBackend2(newValue);
      }, 1000); 
    };

    watch(SliderValue1, (newValue, oldValue) => {
      if (newValue !== oldValue) {
        debounceSendDataToBackend(newValue);
      }
    });

    watch(SliderValue2, (newValue, oldValue) => {
      if (newValue !== oldValue) {
        debounceSendDataToBackend2(newValue);
      }
    });

    const sendDataToBackend = (value: number) => {
      axios.post('/textlen', { data: value })
        .then(response => {
          console.log(response.data); // 处理响应数据
        })
        .catch(error => {
          console.error('Error:', error); // 处理错误
        });
    };

    const sendDataToBackend2 = (value: number) => {
      axios.post('/historylen', { data: value })
        .then(response => {
          console.log(response.data); // 处理响应数据
        })
        .catch(error => {
          console.error('Error:', error); // 处理错误
        });
    };
</script>

<style scoped>
pre {
  font-family: -apple-system, "Noto Sans", "Helvetica Neue", Helvetica,
    "Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB",
    "Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN",
    "Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti",
    SimHei, "WenQuanYi Zen Hei Sharp", sans-serif;
}
</style>